# coding: utf-8
# @Author: 吴启新

import pandas as pd


def calculate_contribution(data: pd.DataFrame, num_classes: int, subjects_info: list[dict]) -> pd.DataFrame:
    """计算贡献度主函数"""
    try:
        # 初始化贡献度DataFrame
        contribution_data, total_score_index, num_other_subjects = initialize_contribution_dataframe(num_classes,
                                                                                                     subjects_info)

        # 填充基本信息：班级、班主任、总分、排名
        fill_basic_info(contribution_data, data, num_classes,
                        subjects_info[total_score_index]['row'] if total_score_index != -1 else 0)

        # 填充科目表头信息
        subject_columns_start = fill_subject_headers(contribution_data, subjects_info, total_score_index)

        # 填充各科目数据
        fill_subject_data(contribution_data, data, subjects_info, total_score_index, subject_columns_start, num_classes)

        # 计算各班级排名平均值
        calculate_rank_averages(contribution_data, subjects_info, total_score_index, num_classes)

        # 计算各科目贡献度
        calculate_contributions(contribution_data, subjects_info, total_score_index, num_classes)

        # 删除辅助列"排名平均值"
        contribution_data = remove_rank_avg_column(contribution_data)

        return contribution_data
    except Exception as e:
        print(f"计算贡献度时出错: {e}")
        return pd.DataFrame()


def remove_rank_avg_column(contribution_data: pd.DataFrame) -> pd.DataFrame:
    """删除排名平均值列"""
    try:
        # 查找"排名平均值"列
        rank_avg_col_index = None
        for col_index in range(contribution_data.shape[1]):
            if contribution_data.iloc[0, col_index] == "排名平均值":
                rank_avg_col_index = col_index
                break
        
        if rank_avg_col_index is not None:
            # 删除排名平均值列
            contribution_data = contribution_data.drop(columns=[rank_avg_col_index])
            # 重置列索引
            contribution_data.columns = range(contribution_data.shape[1])
        return contribution_data
    except Exception as e:
        print(f"删除排名平均值列时出错: {e}")
        return contribution_data


def initialize_contribution_dataframe(num_classes: int, subjects_info: list[dict]) -> tuple:
    """初始化贡献度DataFrame"""
    # 计算科目数量（排除总分）
    total_score_index = 0 if subjects_info and subjects_info[0]['subject'] == '总分' else -1
    num_other_subjects = len(subjects_info) - 1 if total_score_index != -1 else len(subjects_info)

    # 计算表格的行数和列数
    rows = num_classes + 1  # 班级数+总计行
    cols = 4 + num_other_subjects * 4 + 1  # 总分固定4列 + 每科4个指标 + 1个排名平均值列

    # 创建空的DataFrame, 并填充空字符串
    contribution_data = pd.DataFrame(index=range(rows), columns=range(cols)).fillna('')

    return contribution_data, total_score_index, num_other_subjects


def fill_basic_info(contribution_data: pd.DataFrame, data: pd.DataFrame,
                    num_classes: int, total_score_row: int) -> None:
    """填充基本信息：班级、班主任、总分、排名"""
    from config.config import EXCEL_SETTINGS
    header_offset = EXCEL_SETTINGS['HEADER_OFFSET']
    header_row = total_score_row + header_offset

    # 填充表头
    from config.config import CONTRIBUTION_CONFIG
    fixed_columns = CONTRIBUTION_CONFIG['columns_structure']['fixed_columns']
    for i, column_name in enumerate(fixed_columns):
        contribution_data.iloc[0, i] = column_name

    # 填充班级信息
    for i in range(num_classes):
        if header_row + i < len(data):
            class_name = data.iloc[header_row + i, 0]  # 第1列获取班级名称
            contribution_data.iloc[i + 1, 0] = class_name

    # 填充班主任信息
    for i in range(num_classes):
        if header_row + i < len(data):
            teacher_name = data.iloc[header_row + i, 4]  # 第5列获取班主任名称
            contribution_data.iloc[i + 1, 1] = teacher_name

    # 填充总分信息
    for i in range(num_classes):
        if header_row + i < len(data):
            total_score = data.iloc[header_row + i, 7]  # 第8列获取总分
            contribution_data.iloc[i + 1, 2] = total_score

    # 填充排名信息
    for i in range(num_classes):
        if header_row + i < len(data):
            subject_score = data.iloc[header_row + i, 9]  # 第10列获取排名
            contribution_data.iloc[i + 1, 3] = subject_score


def fill_subject_headers(contribution_data: pd.DataFrame, subjects_info: list[dict],
                         total_score_index: int) -> int:
    """填充科目表头信息"""
    if total_score_index == -1:
        return 4  # 如果没找到总分科目，从第5列开始（索引4）

    subject_columns_start = 4  # 从第5列开始填入科目数据

    from config.config import CONTRIBUTION_CONFIG
    subject_pattern = CONTRIBUTION_CONFIG['columns_structure']['subject_pattern']
    
    for subject_idx, subject_info in enumerate(subjects_info[total_score_index + 1:]):
        if subject_info['subject'] != '总分':
            subject_col_index = subject_columns_start + subject_idx * len(subject_pattern)  # 每个科目占len(subject_pattern)列

            # 填入科任列标题
            contribution_data.iloc[0, subject_col_index] = subject_info['subject']

            # 填入科目名称（作为成绩列的标题）
            contribution_data.iloc[0, subject_col_index + 1] = subject_pattern[1]

            # 填入排名列标题
            contribution_data.iloc[0, subject_col_index + 2] = subject_pattern[2]

            # 填入科目贡献度列标题
            contribution_data.iloc[0, subject_col_index + 3] = subject_pattern[3]

    return subject_columns_start


def fill_subject_data(contribution_data: pd.DataFrame, data: pd.DataFrame,
                      subjects_info: list[dict], total_score_index: int,
                      subject_columns_start: int, num_classes: int) -> None:
    """填充各科目数据"""
    from config.config import EXCEL_SETTINGS
    header_offset = EXCEL_SETTINGS['HEADER_OFFSET']

    # 获取科目模式长度
    from config.config import CONTRIBUTION_CONFIG
    subject_pattern = CONTRIBUTION_CONFIG['columns_structure']['subject_pattern']
    subject_pattern_length = len(subject_pattern)
    
    for subject_idx, subject_info in enumerate(subjects_info[total_score_index + 1:]):
        if subject_info['subject'] != '总分':
            subject_col_index = subject_columns_start + subject_idx * subject_pattern_length  # 每个科目占subject_pattern_length列

            # 计算实际的表头行位置
            subject_header_row = subject_info['row'] + header_offset

            # 填入各班级的科目数据
            subject_data_col = subject_info['col']  # 科目数据所在列

            for i in range(num_classes):
                if subject_header_row + i < len(data):  # 确保不越界
                    # 填入老师姓名
                    teacher_name = data.iloc[subject_header_row + i, subject_data_col]
                    contribution_data.iloc[i + 1, subject_col_index] = teacher_name

                    # 填入科目成绩
                    subject_score = data.iloc[subject_header_row + i, subject_data_col + 2]
                    contribution_data.iloc[i + 1, subject_col_index + 1] = subject_score

                    # 填入科目排名
                    subject_rank = data.iloc[subject_header_row + i, subject_data_col + 3]
                    contribution_data.iloc[i + 1, subject_col_index + 2] = subject_rank

                    # 贡献度列暂时留空


def calculate_rank_averages(contribution_data: pd.DataFrame, subjects_info: list[dict],
                            total_score_index: int, num_classes: int) -> None:
    """计算各班级排名平均值"""
    if total_score_index == -1:
        return

    subject_columns_start = 4  # 从第5列开始是科目数据

    # 计算需要的列数
    from config.config import CONTRIBUTION_CONFIG
    subject_pattern = CONTRIBUTION_CONFIG['columns_structure']['subject_pattern']
    subject_pattern_length = len(subject_pattern)
    
    # 计算最后一个科目贡献度列的索引
    total_subjects = 0
    for subject_info in subjects_info[total_score_index + 1:]:
        if subject_info['subject'] != '总分':
            total_subjects += 1
    
    last_contrib_col_index = 4 + (total_subjects - 1) * subject_pattern_length + 3  # 最后一个科目贡献度列索引
    
    # 确保有足够的列来容纳排名平均值列
    while contribution_data.shape[1] <= last_contrib_col_index:
        # 添加新列
        contribution_data[contribution_data.shape[1]] = ''
    
    # 添加排名平均值列标题
    rank_avg_col_index = last_contrib_col_index + 1  # 在最后一个贡献度列之后添加排名平均值列
    contribution_data.iloc[0, rank_avg_col_index] = "排名平均值"

    # 计算每个班级的排名平均值
    for i in range(num_classes):
        rank_sum = 0
        valid_subjects = 0

        # 获取科目模式长度
        from config.config import CONTRIBUTION_CONFIG
        subject_pattern = CONTRIBUTION_CONFIG['columns_structure']['subject_pattern']
        subject_pattern_length = len(subject_pattern)
        
        # 遍历除总分外的每个科目
        for subject_idx, subject_info in enumerate(subjects_info[total_score_index + 1:]):
            if subject_info['subject'] != '总分':
                subject_col_index = subject_columns_start + subject_idx * subject_pattern_length  # 每个科目占subject_pattern_length列
                rank_col_index = subject_col_index + 2  # 排名列在科目数据的第3列（索引+2）

                # 获取排名值
                rank_value = contribution_data.iloc[i + 1, rank_col_index]
                if pd.notna(rank_value) and isinstance(rank_value, (int, float)):
                    rank_sum += rank_value
                    valid_subjects += 1

        # 计算并填入平均排名
        if valid_subjects > 0:
            avg_rank = rank_sum / valid_subjects
            contribution_data.iloc[i + 1, rank_avg_col_index] = avg_rank
        else:
            contribution_data.iloc[i + 1, rank_avg_col_index] = 0  # 如果没有有效科目，填入0


def calculate_contributions(contribution_data: pd.DataFrame, subjects_info: list[dict],
                            total_score_index: int, num_classes: int) -> None:
    """计算各科目贡献度"""
    if total_score_index == -1:
        return

    subject_columns_start = 4
    
    # 获取排名平均值列索引
    # 计算需要的列数
    from config.config import CONTRIBUTION_CONFIG
    subject_pattern = CONTRIBUTION_CONFIG['columns_structure']['subject_pattern']
    subject_pattern_length = len(subject_pattern)
    
    # 计算最后一个科目贡献度列的索引
    total_subjects = 0
    for subject_info in subjects_info[total_score_index + 1:]:
        if subject_info['subject'] != '总分':
            total_subjects += 1
    
    last_contrib_col_index = 4 + (total_subjects - 1) * subject_pattern_length + 3  # 最后一个科目贡献度列索引
    rank_avg_col_index = last_contrib_col_index + 1  # 排名平均值列在最后一个贡献度列之后

    # 获取科目模式长度
    from config.config import CONTRIBUTION_CONFIG
    subject_pattern = CONTRIBUTION_CONFIG['columns_structure']['subject_pattern']
    subject_pattern_length = len(subject_pattern)
    
    # 计算每个班级每个科目的贡献度: 贡献度 = 100*(班级排名平均值-科目排名)/班级数
    for i in range(num_classes):
        # 获取该班级的排名平均值
        class_avg_rank = contribution_data.iloc[i + 1, rank_avg_col_index]

        # 遍历除总分外的每个科目，计算并填入贡献度
        for subject_idx, subject_info in enumerate(subjects_info[total_score_index + 1:]):
            if subject_info['subject'] != '总分':
                subject_col_index = subject_columns_start + subject_idx * subject_pattern_length  # 每个科目占subject_pattern_length列
                rank_col_index = subject_col_index + 2  # 科目排名列
                contrib_col_index = subject_col_index + 3  # 科目贡献度列

                # 获取科目排名
                subject_rank = contribution_data.iloc[i + 1, rank_col_index]

                # 计算贡献度
                if pd.notna(subject_rank) and isinstance(subject_rank, (int, float)):
                    contribution_value = 100 * (class_avg_rank - subject_rank) / num_classes
                    contribution_data.iloc[i + 1, contrib_col_index] = contribution_value
